<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Go by Example 中文版: 工作池</title>
    <link rel=stylesheet href="site.css">
  </head>
  <script>
      onkeydown = (e) => {
          
          if (e.key == "ArrowLeft") {
              window.location.href = 'tickers';
          }
          
          
          if (e.key == "ArrowRight") {
              window.location.href = 'waitgroups';
          }
          
      }
  </script>
  <body>

    <div class="example" id="worker-pools">
      <h2><a href="./">Go by Example 中文版</a>: 工作池</h2>
      
      <table>
        
        <tr>
          <td class="docs">
            <p>在这个例子中，我们将看到如何使用协程与通道实现一个_工作池_。</p>

          </td>
          <td class="code empty leading">
            
          
          </td>
        </tr>
        
        <tr>
          <td class="docs">
            
          </td>
          <td class="code leading">
            <a href="http://play.golang.org/p/7_VRwKNWCWt"><img title="Run code" src="play.png" class="run" /></a><img title="Copy code" src="clipboard.png" class="copy" />
          <div class="highlight"><pre><span class="kn">package</span> <span class="nx">main</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            
          </td>
          <td class="code leading">
            
          <div class="highlight"><pre><span class="kn">import</span> <span class="p">(</span>
    <span class="s">&quot;fmt&quot;</span>
    <span class="s">&quot;time&quot;</span>
<span class="p">)</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            <p>这是 worker 程序，我们会并发的运行多个 worker。
worker 将在 <code>jobs</code> 频道上接收工作，并在 <code>results</code> 上发送相应的结果。
每个 worker 我们都会 sleep 一秒钟，以模拟一项昂贵的（耗时一秒钟的）任务。</p>

          </td>
          <td class="code leading">
            
          <div class="highlight"><pre><span class="kd">func</span> <span class="nx">worker</span><span class="p">(</span><span class="nx">id</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">jobs</span> <span class="o">&lt;-</span><span class="kd">chan</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">results</span> <span class="kd">chan</span><span class="o">&lt;-</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="nx">j</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">jobs</span> <span class="p">{</span>
        <span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;worker&quot;</span><span class="p">,</span> <span class="nx">id</span><span class="p">,</span> <span class="s">&quot;started  job&quot;</span><span class="p">,</span> <span class="nx">j</span><span class="p">)</span>
        <span class="nx">time</span><span class="p">.</span><span class="nx">Sleep</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">)</span>
        <span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;worker&quot;</span><span class="p">,</span> <span class="nx">id</span><span class="p">,</span> <span class="s">&quot;finished job&quot;</span><span class="p">,</span> <span class="nx">j</span><span class="p">)</span>
        <span class="nx">results</span> <span class="o">&lt;-</span> <span class="nx">j</span> <span class="o">*</span> <span class="mi">2</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            
          </td>
          <td class="code leading">
            
          <div class="highlight"><pre><span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            <p>为了使用 worker 工作池并且收集其的结果，我们需要 2 个通道。</p>

          </td>
          <td class="code leading">
            
          <div class="highlight"><pre>    <span class="kd">const</span> <span class="nx">numJobs</span> <span class="p">=</span> <span class="mi">5</span>
    <span class="nx">jobs</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">numJobs</span><span class="p">)</span>
    <span class="nx">results</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">numJobs</span><span class="p">)</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            <p>这里启动了 3 个 worker，
初始是阻塞的，因为还没有传递任务。</p>

          </td>
          <td class="code leading">
            
          <div class="highlight"><pre>    <span class="k">for</span> <span class="nx">w</span> <span class="o">:=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">w</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="p">;</span> <span class="nx">w</span><span class="o">++</span> <span class="p">{</span>
        <span class="k">go</span> <span class="nx">worker</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span> <span class="nx">jobs</span><span class="p">,</span> <span class="nx">results</span><span class="p">)</span>
    <span class="p">}</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            <p>这里我们发送 5 个 <code>jobs</code>，
然后 <code>close</code> 这些通道，表示这些就是所有的任务了。</p>

          </td>
          <td class="code leading">
            
          <div class="highlight"><pre>    <span class="k">for</span> <span class="nx">j</span> <span class="o">:=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">j</span> <span class="o">&lt;=</span> <span class="nx">numJobs</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span> <span class="p">{</span>
        <span class="nx">jobs</span> <span class="o">&lt;-</span> <span class="nx">j</span>
    <span class="p">}</span>
    <span class="nb">close</span><span class="p">(</span><span class="nx">jobs</span><span class="p">)</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            <p>最后，我们收集所有这些任务的返回值。
这也确保了所有的 worker 协程都已完成。
另一个等待多个协程的方法是使用<a href="waitgroups">WaitGroup</a>。</p>

          </td>
          <td class="code">
            
          <div class="highlight"><pre>    <span class="k">for</span> <span class="nx">a</span> <span class="o">:=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">a</span> <span class="o">&lt;=</span> <span class="nx">numJobs</span><span class="p">;</span> <span class="nx">a</span><span class="o">++</span> <span class="p">{</span>
        <span class="o">&lt;-</span><span class="nx">results</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></div>

          </td>
        </tr>
        
      </table>
      
      <table>
        
        <tr>
          <td class="docs">
            <p>运行程序，显示 5 个任务被多个 worker 执行。
尽管所有的工作总共要花费 5 秒钟，但该程序只花了 2 秒钟，
因为 3 个 worker 是并行的。</p>

          </td>
          <td class="code leading">
            
          <div class="highlight"><pre><span class="gp">$</span> <span class="nb">time</span> go run worker-pools.go 
<span class="go">worker 1 started  job 1</span>
<span class="go">worker 2 started  job 2</span>
<span class="go">worker 3 started  job 3</span>
<span class="go">worker 1 finished job 1</span>
<span class="go">worker 1 started  job 4</span>
<span class="go">worker 2 finished job 2</span>
<span class="go">worker 2 started  job 5</span>
<span class="go">worker 3 finished job 3</span>
<span class="go">worker 1 finished job 4</span>
<span class="go">worker 2 finished job 5</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            
          </td>
          <td class="code">
            
          <div class="highlight"><pre><span class="go">real    0m2.358s</span>
</pre></div>

          </td>
        </tr>
        
      </table>
      
      
      <p class="next">
        下一个例子: <a href="waitgroups">WaitGroup</a>
      </p>
      
      <p class="footer">
        <a href="https://twitter.com/mmcgrana">@mmcgrana</a> 编写 | <a href="https://github.com/gobyexample-cn">gobyexample-cn</a> 翻译 | <a href="https://github.com/gobyexample-cn/gobyexample/issues">反馈</a> | <a href="https://github.com/gobyexample-cn/gobyexample">源码</a> | <a href="https://github.com/mmcgrana/gobyexample#license">license</a>      </p>
      </p>
    </div>
    <script>
      var codeLines = [];
      codeLines.push('');codeLines.push('package main\u000A');codeLines.push('import (\u000A    \"fmt\"\u000A    \"time\"\u000A)\u000A');codeLines.push('func worker(id int, jobs \x3C-chan int, results chan\x3C- int) {\u000A    for j := range jobs {\u000A        fmt.Println(\"worker\", id, \"started  job\", j)\u000A        time.Sleep(time.Second)\u000A        fmt.Println(\"worker\", id, \"finished job\", j)\u000A        results \x3C- j * 2\u000A    }\u000A}\u000A');codeLines.push('func main() {\u000A');codeLines.push('    const numJobs = 5\u000A    jobs := make(chan int, numJobs)\u000A    results := make(chan int, numJobs)\u000A');codeLines.push('    for w := 1; w \x3C= 3; w++ {\u000A        go worker(w, jobs, results)\u000A    }\u000A');codeLines.push('    for j := 1; j \x3C= numJobs; j++ {\u000A        jobs \x3C- j\u000A    }\u000A    close(jobs)\u000A');codeLines.push('    for a := 1; a \x3C= numJobs; a++ {\u000A        \x3C-results\u000A    }\u000A}\u000A');codeLines.push('');codeLines.push('');
    </script>
    <script src="site.js" async></script>
  </body>
</html>
